﻿#if UNITY_EDITOR
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;


/*5. 设计一个生成Data保存类的程序(小游戏设计)
字段:
实物字段(金币 等级 所在关卡):默认值
虚拟字段(道具是否存在过)

设计生成器:
int levelNum entity 1
string levelKeyDisappear virtual 1
string item virtualMore 0
stringAry itemAry entity 0            //解析成List操作, 存储的时候存在一个字符串中 0_1_1_1_1
*/

/*
 *
 *
 * */

namespace UFrame
{
    /// <summary>
    /// 根据规则生成 PlayerPrefs保存的数据类
    /// </summary>
    public class PlayerPrefsCodeGenerate
    {
        public static string path = "BawAsset/PlayerPrefs/";
        public static string outPath = "Script/";

        [MenuItem("Plateface/ORM/PlayerPrefsCode")]
        public static void PlayerPrefsCode()
        {
            var comPath = Path.Combine(Application.dataPath, path);
            string classPath = Path.Combine(Application.dataPath, outPath);

            Debug.Log("路径:" + comPath);


            if (!Directory.Exists(comPath))
            {
                Debug.LogError("生成代码路径不存在 " + comPath);
                return;
            }

            DirectoryInfo d = new DirectoryInfo(comPath);
            var files = d.GetFiles("*.txt");

            var templateClass = DefineScript.templateClass;
            foreach (var item in files)
            {
                string className = Path.GetFileNameWithoutExtension(item.Name);

                string s = File.ReadAllText(item.FullName, Encoding.UTF8);
                var allLine = s.Split(new string[] {"\r\n"}, StringSplitOptions.None);

                var classInfoSB = GenerateClass(allLine);

                templateClass = templateClass.Replace("${className}", className);
                templateClass = templateClass.Replace("${classContent}", classInfoSB.GetClassContent());
                templateClass = templateClass.Replace("${classLoad}",
                    DefineScript.loadMethod.Replace("${classLoad}", classInfoSB.initMethod.ToString()));
                templateClass = templateClass.Replace("${classSave}",
                    DefineScript.saveMethod.Replace("${classSave}", classInfoSB.saveMethod.ToString()));

                var fileOut = Path.Combine(classPath, className);
                File.WriteAllText(fileOut + ".cs", templateClass);
                Debug.Log(fileOut + ".cs");
            }
        }

        public static string[] SplitSpacing(string line)
        {
            string[] mm = Regex.Split(line, "\\s+", RegexOptions.IgnoreCase);
            return mm;
        }

        private static PlayerRefsSB GenerateClass(string[] allLine)
        {
            PlayerRefsSB p = new PlayerRefsSB();
            foreach (var line in allLine)
            {
                if (string.IsNullOrEmpty(line))
                    continue;

                StringComparison ion = StringComparison.OrdinalIgnoreCase;
                string[] charAry = SplitSpacing(line);
                string fieldType = charAry[0];
                string fieldName = charAry[1];
                string fieldDes = charAry[2];
                bool isEntity = fieldDes.Equals("entity", ion);
                bool isVirtual = fieldDes.Equals("virtual", ion);
                bool isVirtualMore = fieldDes.Equals("virtualMore", ion);
                bool isVirtualOne = fieldDes.Equals("virtualOne", ion);
                bool isList = false;
                string defaultVal = string.Empty;
                    if(charAry.Length > 3)
                defaultVal = charAry[3];

                string unName = fieldName + "Un";
                p.fieldUn.AppendLine(string.Format("private string {0} = \"{1}\";", unName, unName));
                p.fieldUn.AppendLine();

                if (fieldType.EndsWith("Ary"))
                {
                    isList = true;
                    fieldType = fieldType.Substring(0, fieldType.Length - 3);
                }

                string maxFieldType = fieldType.Substring(0, 1).ToUpper() + fieldType.Substring(1);
                string maxFieldName = fieldName.Substring(0, 1).ToUpper() + fieldName.Substring(1);

                GenerateInfo info = new GenerateInfo();
                info.fieldType = fieldType;
                info.fieldName = fieldName;
                info.fieldDes = fieldDes;
                info.isList = isList;
                info.defaultVal = defaultVal;
                info.unName = unName;
                info.p = p;
                info.maxFieldType = maxFieldType;
                info.maxFieldName = maxFieldName;

                if (isList)
                {
                    GenerateAry(info);
                }
                else if (isEntity)
                {
                    GenerateEntity(info);
                }
                else if (isVirtual)
                {
                    GenerateVirtual(info);
                }
                else if (isVirtualMore)
                {
                    GenerateVirtualMore(info);
                }
            }


            return p;
        }

        public static void GenerateAry(GenerateInfo info)
        {
            string fieldType = info.fieldType;
            string fieldName = info.fieldName;
            string defaultVal = info.defaultVal;
            string unName = info.unName;
            PlayerRefsSB p = info.p;
            string maxFieldName = info.maxFieldName;
            string maxFieldType = info.maxFieldType;

            if (defaultVal.StartsWith("\"") && defaultVal.EndsWith("\""))
            {
            }
            else
            {
                defaultVal = "\"" + defaultVal + "\"";
            }

            p.fieldCall.AppendLine(string.Format("public Action<int,{0}> On{1};", fieldType, maxFieldName));
            p.field.AppendLine(string.Format("private string {1} = {2};", fieldType, fieldName, defaultVal));

            string setMethod = "public void Set{0}(int index,{1} value)"
                               + "{{\n"
                               + "string [] ary = {2}.Split('_'); \n"
                               + "ary[index] = value.ToString(); \n"
                               + "string s = string.Join(\"_\",ary); \n"
                               + "PlayerPrefs.SetString({3},s); \n"
                               + "if(On{4} != null) \n"
                               + "    On{4}(index,value); \n"
                               + "}}\n";
            p.virtualMethod.AppendLine(string.Format(setMethod, maxFieldName, fieldType, fieldName, unName,
                maxFieldName,
                defaultVal));


            string getMethod = string.Empty;
            if (fieldType == "string")
            {
                getMethod = "public {0} Get{1}(int index)"
                            + "{{\n"
                            + "string [] ary = {2}.Split('_') ;\n"
                            + "string num = ary[index]; \n"
                            + "return num; \n"
                            + "}}\n";
                p.virtualMethod.AppendLine(string.Format(getMethod, fieldType, maxFieldName, fieldName,
                    defaultVal));
            }
            else
            {
                getMethod = "public {0} Get{1}(int index)"
                            + "{{\n"
                            + "string [] ary = {2}.Split('_'); \n"
                            + "var num = System.Convert.ToInt32(ary[index]); \n"
                            + "return num; \n"
                            + "}}\n";
                p.virtualMethod.AppendLine(string.Format(getMethod, fieldType, maxFieldName, fieldName, defaultVal));
            }

            p.initMethod.AppendLine(string.Format("{0} = PlayerPrefs.GetString({1}, {2});\n", fieldName, unName,
                defaultVal, maxFieldType));

            p.saveMethod.AppendLine(string.Format("PlayerPrefs.SetString({0}, {1});", unName, fieldName,
                maxFieldType));
        }

        public static void GenerateVirtual(GenerateInfo info)
        {
            string fieldType = info.fieldType;
            string defaultVal = info.defaultVal;
            string unName = info.unName;
            PlayerRefsSB p = info.p;
            string maxFieldName = info.maxFieldName;

            string setMethod = "public void Set{0}(string valStr)"
                               + "{{\n"
                               + "PlayerPrefs.SetString({1}, valStr);\n"
                               + "}}\n";

            string getMethod = "public {0} Get{1}()"
                               + "{{\n"
                               + "return PlayerPrefs.GetString({2}, \"\");\n"
                               + "}}\n";

            p.virtualMethod.AppendLine(string.Format(setMethod, maxFieldName, unName, defaultVal));
            p.virtualMethod.AppendLine(string.Format(getMethod, fieldType, maxFieldName, unName, defaultVal));
            //p.field.AppendLine(string.Format("private {0} {1} = {2}", fieldType, fieldName, defaultVal));
        }

        public static void GenerateEntity(GenerateInfo info)
        {
            string fieldType = info.fieldType;
            string fieldName = info.fieldName;
            string defaultVal = info.defaultVal;
            string unName = info.unName;
            PlayerRefsSB p = info.p;
            string maxFieldName = info.maxFieldName;
            string maxFieldType = info.maxFieldType;

            p.fieldCall.AppendLine(string.Format("public Action<{0}> On{1};", fieldType, maxFieldName));
            p.field.AppendLine(string.Format("private {0} {1} = {2};", fieldType, fieldName, defaultVal));

            p.property.AppendLine(string.Format("public {0} {1} \n" +
                                                "{{\n" +
                                                "get {{ return {2}; }}\n" +
                                                "set{{\n" +
                                                "if({2} == value)\n" +
                                                "return;\n" +
                                                "{2} = value;\n" +
                                                "PlayerPrefs.Set{4}({3}, {2});\n" +
                                                "if(On{1} != null)\n" +
                                                "On{1}({2});\n" +
                                                "}}\n" +
                                                "}}\n", fieldType, maxFieldName, fieldName, unName,
                maxFieldType));

            p.initMethod.AppendLine(string.Format("{0} = PlayerPrefs.Get{3}({1}, {2});\n", fieldName, unName,
                defaultVal, maxFieldType));

            p.saveMethod.AppendLine(string.Format("PlayerPrefs.Set{2}({0}, {1});", unName, fieldName,
                maxFieldType));
        }

        public static void GenerateVirtualMore(GenerateInfo info)
        {
            string fieldType = info.fieldType;
            string defaultVal = info.defaultVal;
            string unName = info.unName;
            PlayerRefsSB p = info.p;
            string maxFieldName = info.maxFieldName;
            string maxFieldType = info.maxFieldType;

            string isMethod = string.Empty;
            string setMethod = string.Empty;
            string getMethod = string.Empty;
            if (fieldType == "int")
            {
                setMethod = "public void Set{0}(string name,int val)"
                            + "{{\n"
                            + "PlayerPrefs.SetInt(\"{0}_\" + name, val);\n"
                            + "}}\n";

                getMethod = "public {0} Get{1}(string name)"
                            + "{{\n"
                            + "return PlayerPrefs.GetInt(\"{1}_\"  + name, 0);\n"
                            + "}}\n";

                isMethod = "public bool Is{0}(string name)"
                           + "{{\n"
                           + "return PlayerPrefs.GetInt(\"{1}_\"  + name, 0) > 0;\n"
                           + "}}\n";
            }

            if (fieldType == "string")
            {
                setMethod = "public void Set{0}(string name,string valStr)"
                            + "{{\n"
                            + "PlayerPrefs.SetString(\"{0}_\" + name, valStr);\n"
                            + "}}\n";

                getMethod = "public {0} Get{1}(string name)"
                            + "{{\n"
                            + "return PlayerPrefs.GetString(\"{1}_\"  + name, \"\");\n"
                            + "}}\n";

                isMethod = "public bool Is{0}(string name)"
                           + "{{\n"
                           + "return PlayerPrefs.GetString(\"{1}_\"  + name, \"\") == \"1\";\n"
                           + "}}\n";
            }

            p.virtualMethod.AppendLine(string.Format(isMethod, maxFieldName, maxFieldName, defaultVal));
            p.virtualMethod.AppendLine(string.Format(setMethod, maxFieldName, unName, defaultVal));
            p.virtualMethod.AppendLine(string.Format(getMethod, fieldType, maxFieldName, unName, defaultVal));
        }

        public class GenerateInfo
        {
            public PlayerRefsSB p;
            public string fieldType;
            public string fieldDes;
            public string maxFieldName;
            public string fieldName;
            public string defaultVal;
            public string unName;
            public string maxFieldType;
            public bool isList;
        }

        public class PlayerRefsSB
        {
            public StringBuilder fieldCall = new StringBuilder();
            public StringBuilder field = new StringBuilder();
            public StringBuilder fieldUn = new StringBuilder();
            public StringBuilder property = new StringBuilder();
            public StringBuilder initMethod = new StringBuilder();
            public StringBuilder saveMethod = new StringBuilder();
            public StringBuilder virtualMethod = new StringBuilder();

            public string GetClassContent()
            {
                return field.ToString() + fieldCall + fieldUn + property + virtualMethod;
            }
        }


        public class DefineScript
        {
            public static string boolProperty = "private {0} {1} \n" +
                                                "{{\n" +
                                                "get {{ return {2} > 0; }}\n" +
                                                "set{{\n" +
                                                "if({2} == value)\n" +
                                                "return;\n" +
                                                "{2} = value\n" +
                                                "PlayerPrefs.SetInt({3}, {2});\n" +
                                                "}}\n" +
                                                "}}\n";


            public static string templateClass = "using System.Collections;\n" +
                                                 "using System.Collections.Generic;\n" +
                                                 "using System;\n" +
                                                 "using UnityEngine;\n" +
                                                 "using System.IO;\n" +
                                                 //"public class ${className} : Singleton<${className}>\n" +
                                                 "public class ${className} \n" +
                                                 "{\n" +
                                                 "private static ${className} i;" +
                                                 "public static ${className} I\n" +
                                                 "{\n" +
                                                 "get\n" +
                                                 "{\n" +
                                                 "if (i == null)\n" +
                                                 "i = new ${className}();\n" +
                                                 "return i;\n" +
                                                 "}\n" +
                                                 "}\n" +
                                                 "${classContent}\n" +
                                                 "${classLoad}\n" +
                                                 "${classSave}\n" +
                                                 "}\n";

            public static string loadMethod = "public void Load()\n" +
                                              "{\n" +
                                              "${classLoad}\n" +
                                              "}\n";

            public static string saveMethod = "public void Save()\n" +
                                              "{\n" +
                                              "${classSave}\n" +
                                              "}\n";
        }
    }
}

#endif